/*
 *      Human_parser.c
 *      
 *      Copyright 2009 Daniele Ricci <denn86@gmail.com>, Luca Saccagi <luksak86@gmail.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#define _VERSION "dilca - Human Parser (v0.0.3)"
#define _VERSION1 "0.0.3"

/* 
		gcc `pkg-config --cflags --libs vortex` your-program.c -o your-program
 */


#include <vortex.h>
#include <string.h>
#include <time.h>


#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

#ifdef _WIN32
#include <winf.h>
#endif
#define PLAIN_PROFILE "http://fact.aspl.es/profiles/plain_profile" 


/* Numero e Lunghezza dei Comandi */
#define COMMAND_NUMBER 9
#define COMMAND_MAX_LENGHT 100
/* Gestione Comandi disponibili */
#define _QUIT		0
#define _HOST		1
#define _PORT		2
#define _CONNECT	3
#define _SELECT		4
#define _CLOSE		5
#define _STATUS		6
#define _USER		7
#define _PASSWORD	8
/* Gestione Errori */
#define _NOCOMMAND	-1
#define _NOTOP		-2


VortexStatus st;
VortexConnection *cn;
VortexChannel *ch;
bool connected = FALSE;
bool CMDREADY = FALSE;
bool CHANNELREADY = FALSE;
bool ans_num_received = FALSE;
int msg_no;
int msg_cnt;
int ans_num;
int input_case = _NOCOMMAND;
char *st_m;
char host[1024]="";
char port[1024]="";
char input[1024]="";
char user[1024]="bob";
char password[1024]="secret";
char commands[COMMAND_NUMBER][COMMAND_MAX_LENGHT] = {
		"quit",
		"host",
		"port",
		"connect",
		"select",
		"close",
		"status",
		"user",
		"password"
	};

void version(int argc, char **argv);
void init(void);
void frame_received(VortexChannel *ch,VortexConnection *cn,VortexFrame *frame, axlPointer user_data);
int hp_cmd(char command[1024]);
void _command1(void);
void _command2(void);
void _command3(void);
void _command4(void);
void _command5(void);
void _command6(void);
void _command7(void);
void _command8(void);




int main(int argc,char **argv){
	version(argc,argv);
 	init();
	while(input_case != _QUIT){
		connected ? printf("[DILCA][%s:%s]",host,port) : printf("[DILCA]");
		CMDREADY ? CMDREADY : printf(" >"); 
		switch((CMDREADY ? (input_case) : (input_case = hp_cmd(gets(input))))){
			case(_NOCOMMAND):
				CMDREADY=FALSE;
				break;
			case(_NOTOP):
				printf("[ERR] > Operation not permitted\n");
				CMDREADY=FALSE;
				break;
			case(_HOST):
				_command1();
				break;
			case(_PORT):
				_command2();
				break;
			case(_CONNECT):
				_command3();
				break;
			case(_SELECT):
				_command4();
				break;
			case(_CLOSE):
				_command5();
				break;
			case(_STATUS):
				_command6();
				break;
			case(_USER):
				_command7();
				break;
			case(_PASSWORD):
				_command8();
				break;
		}
	}	
	vortex_exit();	
	return 0;
}

#ifdef _WIN32
static void version(int argc, char **argv){
#else
void version(int argc, char **argv){
#endif
	if(argc <= 1) return;
	if(strcmp(argv[1],"-v")==0){ printf(_VERSION1); printf("\n"); exit(0); }
	if(strcmp(argv[1],"-V")==0){ printf(_VERSION); printf("\n"); exit(0); }
	return;
}

void frame_received(VortexChannel *ch,VortexConnection *cn,VortexFrame *frame, axlPointer user_data){
	int size = vortex_frame_get_payload_size(frame);
	if(size > 10){
		msg_cnt++;
		printf("\n(%d) %s",size,(char *)vortex_frame_get_payload(frame));
	}else if(size == 10){
		sscanf(vortex_frame_get_payload(frame),"%10d",&ans_num);
		ans_num_received=true;
	}
	if(ans_num_received && (msg_cnt == ans_num)) CHANNELREADY=TRUE;
}

void init(void){
	vortex_init();
	#ifdef _WIN32
	system("cls");
	#else
	system("clear");
	#endif
	
	printf("\n********************************************************\n* D.I.L.C.A (Human Parser), Copyright (C) 2009         *\n* Authors: Daniele Ricci and Luca Saccagi              *\n* D.I.L.C.A (Human Parser) comes with ABSOLUTELY NO    *\n* WARRANTY. This is free software, and you are         *\n* welcome to redistribute it under certain conditions. *\n********************************************************\n\n");
 	
	vortex_connection_set_auto_tls(true,true,NULL);
	return;
}

int hp_cmd(char command[1024]){
	bool founded = FALSE;
	int loop = 0;
	int command_type = 0;
	int ret = 0;
	
	if(strlen(command)>0){
		for(command_type=0,founded=FALSE;(command_type <= COMMAND_NUMBER) && founded==FALSE;command_type=command_type+1){
			if(command_type!=4){
				if(strncasecmp(commands[command_type],command,strlen(commands[command_type]))==0) founded=TRUE;
			} else {
				if(strncasecmp(commands[command_type],&command[7],6)==0) founded=TRUE;
				else if(strncasecmp(commands[command_type],&command[8],6)==0) founded=TRUE;
			}
		}
	}else return -1;
	return (founded == TRUE ? (command_type -1) :  -2);
}

void _command1(){
	printf("[DILCA][SET] >");
	gets(host);
	CMDREADY=FALSE;
	return;
}
void _command2(){
	printf("[DILCA][SET] >");
	gets(port);
	CMDREADY=FALSE;
}
void _command3(){
	cn=vortex_connection_new(host, port, NULL, NULL);
	if(!vortex_connection_is_ok(cn,false)){
		fprintf(stderr,"[DILCA][ERR] > Unable to connect remote server, error was: %s\n",vortex_connection_get_message(cn));
		vortex_connection_close(cn);
		return;
	}
	if(vortex_connection_is_tlsficated(cn)){
		ch=vortex_channel_new(cn,0,PLAIN_PROFILE,NULL,NULL,NULL,NULL,NULL,NULL);
		if(ch==NULL){
			perror("[DILCA][ERR] > Unable to create the channel..\n");
			vortex_connection_close(cn);
			return;
		}
		if(!vortex_sasl_is_enabled()){									//1: check if SASL is activated
			printf("[DILCA][ERR] > Unable to initialize SASL profiles.\n");
		}											
		vortex_sasl_set_propertie(cn,VORTEX_SASL_AUTH_ID,user,NULL);	//2: set required SASL properties
		vortex_sasl_set_propertie(cn,VORTEX_SASL_PASSWORD,password,NULL);
		vortex_sasl_start_auth_sync(cn,VORTEX_SASL_CRAM_MD5,&st,&st_m);	//3: begin SASL negotiation
		if(vortex_sasl_is_authenticated(cn)){							//4: check of authentication
			printf("[DILCA][INF] > SASL negotiation OK, user %s is authenticated\n",vortex_sasl_get_propertie(cn, VORTEX_SASL_AUTH_ID));
			ch=vortex_channel_new(cn,0,PLAIN_PROFILE,NULL,NULL,frame_received,NULL,NULL,NULL);
			if(ch==NULL){
				printf("[DILCA][ERR] > Unable to create the channel..\n");
				vortex_connection_close(cn);
				return;
			}else connected=TRUE;
		}else {
			printf ("[DILCA][ERR] > SASL negotiation have failed: status=%d, message=%s\n",st,st_m);
		}
	}else{
		printf("[DILCA][ERR] > Unable to use TLS profile\n");
	}
	//vortex_channel_set_serialize(ch,1);
	CMDREADY=FALSE;	
}
void _command4(){
	if(!connected){
		input_case = -2;
		CMDREADY=TRUE;
	}else{
		msg_cnt=0;
		ans_num=-1;
		ans_num_received = FALSE;
		CHANNELREADY=FALSE;
		if(!vortex_channel_send_msg(ch,input,strlen(input),&msg_no)){
			printf("[DILCA][%s:%s][ERR] > Unable to send messages\n",host,port);
			input_case = 5;
			CMDREADY=TRUE;
		}else{
			//while(!vortex_channel_is_ready(ch));
			while(!CHANNELREADY) usleep(100);
			CMDREADY=FALSE;
			printf("\n[DILCA][%s:%s][INF] > %d Results\n",host,port,ans_num);
		}
	}
}

void _command5(){
	if(connected){
		printf("[DILCA][INF] > Closing connection from %s\n",host,port,host);
		vortex_connection_close(cn);
		connected=FALSE;
		CMDREADY=FALSE;
	}else {
		input_case = -2;
		CMDREADY=TRUE;
	}
}
void _command6(){
	connected ? printf("[DILCA][INF] > Already Connected\n") : printf("[DILCA][INF] > Not Connected\n");
	strlen(host) > 0 ? printf("[DILCA][INF] > Host: %s\n",host) : printf("[DILCA][INF] > Host: ND\n");
	strlen(port) > 0 ? printf("[DILCA][INF] > Port: %s\n",port) : printf("[DILCA][INF] > Port: ND\n");
	strlen(user) > 0 ? printf("[DILCA][INF] > User: %s\n",user) : printf("[DILCA][INF] > User: ND\n");
	strlen(password) > 0 ? printf("[DILCA][INF] > Pass: %s\n",password) : printf("[DILCA][INF] > Pass: ND\n");
	CMDREADY=FALSE;
}

void _command7(){
	printf("[DILCA][SET] >");
	gets(user);
	CMDREADY=FALSE;
}

void _command8(){
	printf("[DILCA][SET] >");
	gets(password);
	CMDREADY=FALSE;
}

